package com.srmt.test.config;

import com.srmt.common.config.ApplicationConfig;
import com.srmt.common.ratelimit.config.RateLimitConfig;
import com.srmt.common.retry.RetryConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

/**
 * Properties文件配置加载器
 * 用于测试环境从properties文件加载ApplicationConfig
 *
 * @author SRMT Development Team
 * @since 3.0.0
 */
public class PropertiesConfigLoader {

    private static final Logger logger = LoggerFactory.getLogger(PropertiesConfigLoader.class);

    /**
     * 从profile加载ApplicationConfig
     *
     * @param profile 配置profile (如 test, prod)
     * @return ApplicationConfig实例
     */
    public static ApplicationConfig loadWithProfile(String profile) {
        if (profile == null || profile.trim().isEmpty()) {
            return load("application.properties");
        }

        String profileConfigFile = "application-" + profile + ".properties";

        // 尝试加载profile配置文件
        if (PropertiesConfigLoader.class.getClassLoader().getResource(profileConfigFile) != null) {
            logger.info("Loading configuration with profile: {}", profile);
            return load(profileConfigFile);
        } else {
            logger.warn("Profile configuration file not found: {}, using default", profileConfigFile);
            return load("application.properties");
        }
    }

    /**
     * 从指定配置文件加载ApplicationConfig
     *
     * @param configFile 配置文件名
     * @return ApplicationConfig实例
     */
    public static ApplicationConfig load(String configFile) {
        Properties props = loadPropertiesFile(configFile);
        return buildConfig(props);
    }

    /**
     * 加载Properties文件
     */
    private static Properties loadPropertiesFile(String filename) {
        Properties props = new Properties();

        try (InputStream is = PropertiesConfigLoader.class.getClassLoader().getResourceAsStream(filename)) {
            if (is != null) {
                props.load(is);
                logger.info("Loaded {} properties from: {}", props.size(), filename);
            } else {
                logger.warn("Configuration file not found in classpath: {}, using defaults", filename);
            }
        } catch (IOException e) {
            logger.error("Failed to load configuration file: {}", filename, e);
        }

        return props;
    }

    /**
     * 从Properties构建ApplicationConfig
     */
    private static ApplicationConfig buildConfig(Properties props) {
        ApplicationConfig config = new ApplicationConfig();

        // ========== 服务配置 ==========
        setProperty(props, "service.platform",
            value -> config.getService().setPlatform(value));
        setIntProperty(props, "service.timeout",
            value -> config.getService().setTimeout(value));
        setBooleanProperty(props, "service.logReqAtDebug",
            value -> config.getService().setLogReqAtDebug(value));

        // 缓存配置
        setBooleanProperty(props, "service.cache.enabled",
            value -> config.getService().getCache().setEnabled(value));
        setIntProperty(props, "service.cache.size",
            value -> config.getService().getCache().setSize(value));
        setIntProperty(props, "service.cache.ttl",
            value -> config.getService().getCache().setTtlMinutes(value));

        // ========== 飞书配置 ==========
        setProperty(props, "feishu.app.id",
            value -> config.getFeishu().setAppId(value));
        setProperty(props, "feishu.app.secret",
            value -> config.getFeishu().setAppSecret(value));
        setProperty(props, "feishu.base.url",
            value -> config.getFeishu().setBaseUrl(value));
        setProperty(props, "feishu.default.folder.token",
            value -> config.getFeishu().setDefaultFolderToken(value));

        // ========== 限流配置 ==========
        setBooleanProperty(props, "ratelimit.enabled",
            value -> config.getRateLimit().setEnabled(value));
        setProperty(props, "ratelimit.limiter.type",
            value -> config.getRateLimit().setProperty("limiter.type", value));

        // 默认限流配置
        setIntProperty(props, "ratelimit.default.qps",
            value -> config.getRateLimit().setDefaultQps(value));
        setLongProperty(props, "ratelimit.default.retry.timeout",
            value -> config.getRateLimit().setDefaultRetryTimeout(value));
        setIntProperty(props, "ratelimit.default.max.retries",
            value -> config.getRateLimit().setDefaultMaxRetries(value));

        // API级别限流配置
        for (String key : props.stringPropertyNames()) {
            if (key.startsWith("ratelimit.api.") && key.endsWith(".qps")) {
                String apiName = extractApiName(key);

                // 获取或创建ApiConfig
                RateLimitConfig.ApiConfig apiConfig = config.getRateLimit().getApiConfig(apiName);

                // QPS
                setIntProperty(props, key, apiConfig::setQps);

                // 重试超时
                String timeoutKey = "ratelimit.api." + apiName + ".retry.timeout";
                setLongProperty(props, timeoutKey, apiConfig::setRetryTimeout);

                // 最大重试次数
                String retriesKey = "ratelimit.api." + apiName + ".max.retries";
                setIntProperty(props, retriesKey, apiConfig::setMaxRetries);

                config.getRateLimit().setApiConfig(apiName, apiConfig);
            }
        }

        // ========== 重试配置 ==========
        setBooleanProperty(props, "retry.enabled",
            value -> config.getRetry().setEnabled(value));
        setIntProperty(props, "retry.max.attempts",
            value -> config.getRetry().setMaxAttempts(value));
        setLongProperty(props, "retry.initial.delay.ms",
            value -> config.getRetry().setInitialDelayMs(value));
        setLongProperty(props, "retry.max.delay.ms",
            value -> config.getRetry().setMaxDelayMs(value));
        setDoubleProperty(props, "retry.backoff.factor",
            value -> config.getRetry().setBackoffFactor(value));

        return config;
    }

    /**
     * 从限流API配置键中提取API名称
     */
    private static String extractApiName(String key) {
        // ratelimit.api.docx.document.create.qps -> docx.document.create
        String withoutPrefix = key.substring("ratelimit.api.".length());
        String withoutSuffix = withoutPrefix.substring(0, withoutPrefix.lastIndexOf('.'));
        return withoutSuffix;
    }

    // ========== 辅助方法 ==========

    private static void setProperty(Properties props, String key, PropertySetter<String> setter) {
        String value = props.getProperty(key);
        if (value != null && !value.trim().isEmpty()) {
            setter.set(value.trim());
        }
    }

    private static void setIntProperty(Properties props, String key, PropertySetter<Integer> setter) {
        String value = props.getProperty(key);
        if (value != null && !value.trim().isEmpty()) {
            try {
                setter.set(Integer.parseInt(value.trim()));
            } catch (NumberFormatException e) {
                logger.warn("Invalid integer value for {}: {}", key, value);
            }
        }
    }

    private static void setLongProperty(Properties props, String key, PropertySetter<Long> setter) {
        String value = props.getProperty(key);
        if (value != null && !value.trim().isEmpty()) {
            try {
                setter.set(Long.parseLong(value.trim()));
            } catch (NumberFormatException e) {
                logger.warn("Invalid long value for {}: {}", key, value);
            }
        }
    }

    private static void setDoubleProperty(Properties props, String key, PropertySetter<Double> setter) {
        String value = props.getProperty(key);
        if (value != null && !value.trim().isEmpty()) {
            try {
                setter.set(Double.parseDouble(value.trim()));
            } catch (NumberFormatException e) {
                logger.warn("Invalid double value for {}: {}", key, value);
            }
        }
    }

    private static void setBooleanProperty(Properties props, String key, PropertySetter<Boolean> setter) {
        String value = props.getProperty(key);
        if (value != null && !value.trim().isEmpty()) {
            setter.set(Boolean.parseBoolean(value.trim()));
        }
    }

    /**
     * 属性设置器接口
     */
    @FunctionalInterface
    private interface PropertySetter<T> {
        void set(T value);
    }
}
